import React from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
import Dom from '../utils/Dom';
import Icon from '../Icon';
import Menu from '../Menu/Menu';

import './Dropdown.less';

class Dropdown extends React.Component {
    displayName = 'Dropdown';

    static defaultProps= {
        align : 'bottom',
        trigger: 'hover',
        transfer: false
    }

    state = {
        open: false,
        dropdownStyle: {}
    }

    openTimer = null;

    onClick = () => {
        if (this.props.disabled) {
            return false;
        }
        this.showOrHide(true);
    }

    onMouseEnter = () => {
        if (this.props.disabled) {
            return false;
        }

        clearTimeout(this.openTimer);
        this.showOrHide(true);
    }

    onMouseLeave = () => {
        if (this.props.disabled) {
            return false;
        }
        this.openTimer = setTimeout(() => {
            this._isMounted && this.setState({
                open: false
            });
        }, 200);
    }

    showOrHide (display) {
        const parent = this.handle.offsetParent;
        let parentRect = {
            left: 0,
            top: 0
        };
        if (parent) {
            parentRect = parent.getBoundingClientRect();
        }
        const {align, transfer} = this.props;
        const relRect = this.handle.getBoundingClientRect();
        this._isMounted && this.setState({
            open: display
        }, () => {
            setTimeout(() => {
                const listRect = this.list.getBoundingClientRect();
                let left = relRect.left - (transfer ? 0 : parentRect.left);
                if (align === 'right') {
                    left = left + relRect.width;
                }
                if (align === 'left') {
                    left = left - relRect.width;
                }
                if (align === 'bottomRight') {
                    left = left + relRect.width - listRect.width;
                }
                if (align === 'bottom') {
                    left = left + relRect.width / 2 - listRect.width / 2;
                }
                let top = relRect.top - (transfer ? 0 : parentRect.top);
                if (align === 'bottomLeft' || align === 'bottom' || align === 'bottomRight') {
                    top = top + relRect.height;
                }

                // 放到body中的时候定位需加上scroll的错位值
                if (transfer) {
                    top = top + document.documentElement.scrollTop;
                    left = left + document.documentElement.scrollLeft;
                }
                this._isMounted && this.setState({
                    dropdownStyle: {
                        top,
                        left
                    }
                });
            });
        });
    }

    componentDidMount () {
        this._isMounted = true;
        if (this.props.trigger === 'click' && !this.props.inner) {
            document.addEventListener('click', this.clickAnyWhere.bind(this), false);
        }

        if (this.props.transfer) {
            this.layer = document.createElement('div');
            // 添加至document.body
            document.body.appendChild(this.layer);
            this._renderLayer();
        }
    }

    componentWillUnmount () {
        this._isMounted = false;
        if (this.props.trigger === 'click' && !this.props.inner) {
            document.removeEventListener('click', this.clickAnyWhere);
        }
        if (this.props.transfer) {
            this.popup && ReactDOM.unmountComponentAtNode(this.popup);
        }
    }

    componentDidUpdate () {
        // 更新时
        if (this.props.transfer) {
            this._renderLayer();
        }
    }

    _renderLayer () {
        ReactDOM.render(this.renderDropdownLayer(), this.layer);
    }

    clickAnyWhere (e) {
        const ele = e.target || e.srcElement;
        const parent = Dom.closest(ele, '.cm-dropdown-outer');
        if (parent && parent == this.wrap) {
            return ;
        } else {
            this._isMounted && this.setState({
                open: false
            });
        }
    }

    onSelect = (item) => {
        if (this.props.onSelect) {
            this.props.onSelect(item);
        }
        this._isMounted && this.setState({
            open: false
        });
    }

    renderDropdown () {
        const {data} = this.props;
        const arr = data && data.map((item, index) => {
            const hasChildren = item.children && item.children.length;
            const clazzName = classNames('cm-dropdown-item', {
                'cm-dropdown-item-divided': item.divided,
                'cm-dropdown-item-disabled': item.disabled,
                'cm-dropdown-item-active': item.selected
            });
            const li = <li key={item.id || index} className={clazzName} onClick={this.onSelect.bind(this, item)}>
                {item.text}
                {
                    item.type !== 'MenuGroup' && hasChildren ? <Icon name='chevron-right' className='cm-menu-submenu-cert'/> : null
                }
            </li>;
            if (hasChildren && item.type !== 'MenuGroup') {
                return <Dropdown inner align={item.align || 'right'} key={item.id || index} data={item.children} trigger='hover'
                    onSelect={this.onSelect}
                >{li}</Dropdown>;
            }
            if (item.type === 'MenuGroup') {
                return <Menu data={[item]} level={-1} onSelectMenu={(a, item) => {
                    this.onSelect(item);
                }}>
                </Menu>;
            }
            return li;
        });
        return <ul className='cm-dropdown-menu'>{arr}</ul>;
    }

    renderDropdownLayer () {
        const {transfer, trigger, className} = this.props;
        const clazzName = classNames('cm-select-dropdown', className, {
            'cm-select-dropdown-open': this.state.open
        });
        
        return <div className={clazzName} ref={f => this.list = f} style={this.state.dropdownStyle} 
            onMouseEnter={trigger === 'hover' && transfer ? this.onMouseEnter : undefined}
            onMouseLeave={trigger === 'hover' && transfer ? this.onMouseLeave : undefined}
        >
            {this.renderDropdown()}
        </div>;
    }

    render () {
        const {className, style, children, trigger, transfer} = this.props;
        const clazzName = classNames('cm-dropdown', className, {
            'cm-dropdown-open': this.state.open,
            'cm-dropdown-transfer': transfer,
            'cm-dropdown-outer': !this.props.inner
        });
        return <div className={clazzName} style={style}  ref={f => this.wrap = f}
            onMouseEnter={trigger === 'hover' ? this.onMouseEnter : undefined}
            onMouseLeave={trigger === 'hover' ? this.onMouseLeave : undefined}>
            <div className='cm-dropdown-rel' ref={f => this.handle = f} 
                onClick={trigger === 'click' ? this.onClick : undefined}
            >
                {children}
            </div>
            {
                !transfer ? this.renderDropdownLayer() : null
            }
        </div>;
    }
}

export default Dropdown;
